#include "FpQThread.h"
#include "FpQThreadWorker.h"
#include <QThread>
#include <QSharedPointer>


class FPQTHREAD_EXPORT FpQThread::FpQThreadAssistant : public QObject {
	Q_OBJECT
public:
	FpQThreadAssistant(QObject* parent = nullptr):QObject(parent) {
		Init();
	};
	~FpQThreadAssistant() {
		if (_thread->isRunning())
		{
			_thread->quit();
			_thread->wait();
		}
		delete _thread;
	};

	void InvokeFn(QObject* obj, const QString& fn) {
		QMetaObject::invokeMethod(_worker, "invokeFn", Qt::QueuedConnection, Q_ARG(QObject*, obj), Q_ARG(const QString&, fn));
	};
	void InvokeFn(QObject* obj, const QString& fn, const QVariantList& params) {
		QMetaObject::invokeMethod(_worker, "invokeFn", Qt::QueuedConnection, Q_ARG(QObject*, obj), Q_ARG(const QString&, fn), Q_ARG(const QVariantList&, params));
	};

	void invokeFn(FpVoidFunc fn) {
		QMetaObject::invokeMethod(_worker, fn);
	};
	void blockingInvokeFn(FpVoidFunc fn,int interval) {
		bool isFinished = false;;
		QMetaObject::invokeMethod(_worker, [fn, &isFinished]() {
			fn();
			isFinished = true;
			});

		while (!isFinished) QThread::currentThread()->msleep(interval);
	};

private:
	void Init(){
		_thread = new QThread();
		_worker = new FpQThreadWorker();
		_worker->moveToThread(_thread);
		connect(_thread, &QThread::finished, _worker, &QObject::deleteLater);
		_thread->start();

	}
private:
	QThread* _thread;
	FpQThreadWorker *_worker;
};



FpQThread::FpQThread(QObject *parent) : QObject(parent)
{
	Init();
}

FpQThread::~FpQThread()
{

}

void FpQThread::InvokeFn(QObject* obj, const QString& fn)
{
	QSharedPointer<FpQThreadAssistant> strongPtr = _assist.toStrongRef();
	if (!strongPtr.isNull()) {
		strongPtr->InvokeFn(obj,fn);
	}
}

void FpQThread::InvokeFn(QObject* obj, const QString& fn, const QVariantList& params)
{
	QSharedPointer<FpQThreadAssistant> strongPtr = _assist.toStrongRef();
	if (!strongPtr.isNull()) {
		strongPtr->InvokeFn(obj, fn,params);
	}
}

void FpQThread::invokeFn(FpVoidFunc fn)
{
	QSharedPointer<FpQThreadAssistant> strongPtr = _assist.toStrongRef();
	if (!strongPtr.isNull()) {
		strongPtr->invokeFn(fn);
	}
}

void FpQThread::blockingInvokeFn(FpVoidFunc fn,int interval)
{
	QSharedPointer<FpQThreadAssistant> strongPtr = _assist.toStrongRef();
	if (!strongPtr.isNull()) {
		strongPtr->blockingInvokeFn(fn,interval);
	}
}

void FpQThread::Init()
{
	QSharedPointer<FpQThreadAssistant> sharePtr = QSharedPointer<FpQThreadAssistant>::create();
	_assist = QWeakPointer<FpQThreadAssistant>(sharePtr);
}
